using System;
using System.Collections.Generic;
using System.Windows;
using System.Xml.Linq;

namespace Ausy.Silverlight.Survey.Common.Configuration
{
    /// <summary>
    /// Cette classe permet de gérer les éléments de configuration
    /// </summary>
    public sealed class ConfigurationManager
    {
        #region Private Members

        /// <summary>
        /// Instance du Gestionnaire de configuration
        /// </summary>
        private static volatile ConfigurationManager instance;

        /// <summary>
        /// Objet de synchronisation
        /// </summary>
        private static object syncRoot = new Object();

        #endregion

        #region Instance Property

        /// <summary>
        /// Propriété Instance du Gestionnaire de configuration
        /// </summary>
        public static ConfigurationManager Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                            instance = new ConfigurationManager();
                    }
                }

                return instance;
            }
        }

        #endregion

        #region Downloader Property

        /// <summary>
        /// Outil de chargement de la configuration
        /// </summary>
        public ConfigurationDownloader Downloader { get; private set; }

        #endregion

        #region AppSettings Property

        /// <summary>
        /// Parametres applicatifs
        /// </summary>
        public Dictionary<string, string> AppSettings { get; private set; }

        #endregion

        #region ContentConfiguration Property

        /// <summary>
        /// Contenu du fichier de configuration
        /// </summary>
        public XElement ContentConfiguration { get; private set; }

        #endregion

        #region ConfigurationFilename Propety

        /// <summary>
        /// Nom du fichier de configuration
        /// </summary>
        public Uri ConfigurationFilename { get; set; }

        #endregion

        #region public ConfigurationDownloadCompleted Event

        /// <summary>
        /// Evènement lorsque le chargement est terminé
        /// </summary>
        public event EventHandler<ConfigurationDownloadCompletedArgs> ConfigurationDownloadCompleted;

        /// <summary>
        /// Evènement lorsque le chargement est terminé
        /// </summary>
        private void OnConfigurationDownloadCompleted(ConfigurationDownloadCompletedArgs e)
        {
            EventHandler<ConfigurationDownloadCompletedArgs> handler = ConfigurationDownloadCompleted;

            if (handler != null)
            {
                handler(this, e);
            }
        }

        #endregion

        #region Private Constructor

        /// <summary>
        /// Constructeur privé
        /// </summary>
        private ConfigurationManager()
        {
            this.AppSettings = new Dictionary<string, string>();
            this.Downloader = new ConfigurationDownloader();
            this.ConfigurationFilename = new Uri(Application.Current.Host.Source.AbsoluteUri.Replace(".xap", ".xml"), UriKind.RelativeOrAbsolute);
        }

        #endregion

        #region DownloadConfiguration Method

        /// <summary>
        /// Cette méthode permet de charger la configuration des applications Settings
        /// </summary>
        public void DownloadConfiguration()
        {
            this.Downloader.ConfigurationDownloadCompleted += new EventHandler<ConfigurationDownloadCompletedArgs>(this.OnConfigurationDownloadCompleted);
            this.Downloader.DownloadConfiguration(this.ConfigurationFilename);
        }

        /// <summary>
        /// Cette méthode permet de traiter le retour asynchrone
        /// </summary>
        /// <param name="sender">ConfigurationManager</param>
        /// <param name="e">Argument contenant les données du fichier de configuration</param>
        void OnConfigurationDownloadCompleted(object sender, ConfigurationDownloadCompletedArgs e)
        {
            if (e.Error == null)
            {
                this.ParseConfiguration(e.Result);
            }
            else
            {
                this.OnConfigurationDownloadCompleted(new ConfigurationDownloadCompletedArgs(string.Empty, e.UserState, e.Error));
            }
        }

        #endregion

        #region ParseConfiguration Method

        /// <summary>
        /// Cette méthode permet de traiter les données
        /// </summary>
        /// <param name="data">donnée du fichier de configuration</param>
        private void ParseConfiguration(string data)
        {
            if (!string.IsNullOrEmpty(data))
            {
                this.AppSettings.Clear();
                var config = XDocument.Parse(data);
                if (config.Root.Elements("appSettings") != null)
                {
                    foreach (var item in config.Root.Elements("appSettings").Elements("add"))
                    {
                        this.AppSettings.Add(item.Attribute("key").Value, item.Attribute("value").Value);
                    }
                }

                this.ContentConfiguration = config.Root;
            }

            this.OnConfigurationDownloadCompleted(new ConfigurationDownloadCompletedArgs(data, null, null));
        }

        #endregion
    }
}
